/* JS的正则表达式可以被用于：
        RegExp对象的exec和test方法；
        String对象的match、replace、search和split方法。 */

// ^	以哪一个元字符作为开始
// $	以哪一个元字符作为结束
// \b 	匹配一个单词边界,注意这是匹配位置 ① \w和\W之间的位置  ②  ^与\w之间的位置  ③ \w与$之间的位置  /\bab/ /bc\b/  /\Bb/  /b\B/ 'aa abc aa'
// \B	非单词边界匹配,注意这是匹配位置  ① \w与\w之间的位置  ② \W与\W之间的位置  ③^与\W之间的位置  ④\W与$之间的位置
// [0-9]+ 匹配多个数字， [0-9] 匹配单个数字，+ 匹配一个或者多个。
// abc$ 匹配字母 abc 并以 abc 结尾，
// $ 为匹配输入字符串的结束位置。
var reg = /^a{1,10}$/ //1到10位只能是a
var reg = /^[a-zA-Z0-9]{1,10}$/ //长度1-10 只能是数字和字母
var reg = /^[a-zA-Z0-9]+[1-9]$/ //字母数字开头,可以有1-n个 ，再以数字结尾
var reg = /^[a-zA-Z0-9_-]{3,5}$/ //含字符、数字、下划线和连接字符 (-)，长度3-5；
var reg = /[^a-zA-Z0-9_-]{3,5}$/ //不含字符、数字、下划线和连接字符 (-)，长度3-5；                  、、、、、、、、、、、、、、、、、、、、
var reg = /\d/ //\d 与 \D 匹配数字和匹配非数字；  相当于[0-9]和[^0-9]
var reg = /\W/ //\w 与 \W 匹配字符和匹配非字符（这里的字符指[A-Z a-z 0-9_]）
var reg = /^a?/
// ?  0-1次   ?? 0次
// *  0-n次； *? 0次
// +  1-n次； +? 1次
// {m,n}  m-n次 尽可能多匹配； {m,n}? m-n 尽可能少匹配；
// {n}    n次；
// {n,}  >=n次；尽可能多匹配；  {n,}? 尽可能少匹配；
// .     除了\n（换行符）以外的的任意字符  注：不是小数点,
// \n	匹配一个换行符。
// \r	匹配一个回车符。
// \s \S	匹配任何空白字符，包括空格、制表符、换页符等等、、	匹配任何非空白字符。
// \t	匹配一个制表符（一个 tab 键，四个空格）。
// \1 \2  代表和第几个分组一样的[值]! ，（）包裹代表分组
// | 或
var reg = /^a|c|e{1,10}$/ // |或
var reg = /^1[3|4|5|7|8]\d{9}$/
var reg = /^[12-48]$/ // 1,2-4,8中取一个 整括号中不识别两位数，整括号内是多个取一个
var reg = /^name$/ // ^$同时存在表示精确匹配 只能是name
var reg = /^(\w+):\/\/[^:/]+(:\d*)?[^# ]*/
// var reg = /(\w+):\/\/([^/:]+)(:\d*)?([^# ]*)/;
var str = 'http://www.axihe.com:80/edu/html/edu/home.html'

// 贪婪匹配和惰性匹配
var r1 = /\d{2,4}/g //贪婪
var r2 = /\d{2,4}?/g //惰性
var s = '123 1234 12345'
s.match(r1) // ["123", "1234", "1234"]
s.match(r2) // ["12", "12", "34", "12", "34"]

// 正则全局字符串替换
var str = 'abc你是谁abc'
var reg = /abc/g
// console.log(str.replace(reg, '哈哈'));

// 单词首字母大写
var str = 'axihe cool cool cool!'
// var newstr = str.split(' ').map(v => {
//     return v.slice(0, 1).toUpperCase() + v.slice(1);
// }).join(' ')

var reg = /\b[a-zA-Z][a-zA-Z]*\b/g

// 格式化时间
// var time = "2020-06-30";
// var reg = /^(\d+)-(\d+)-(\d+)$/g; //因为贪婪性会自动匹配到最多
// var result = time.replace(reg, function () {
//     // console.log(arguments); //这里是匹配的结果
//     return `${arguments[1]}年${arguments[2]}月${arguments[3]}日`
// })
/**
 * 修饰符 img
 * i => ignoreCase   忽略单词大小写匹配
 * m => multiline    可以进行多次匹配 （多行模式，每行都会一次匹配？）
 * g => global       全局匹配
 * s => . 是 匹配除换行符 \n 之外的任何字符，加上 s 之后, . 中包含换行符 \n。
 * */
// console.log(reg.test(str));
// console.log(str.match(reg));

// 分组命名 (ES9)之前的分组是通过数字命名的：
var pattern = /(\d{4})-(\d{2})-(\d{2})/u
var result = pattern.exec('2020-01-05')
// console.log(result[0]); // 打印"2020-01-05"
// console.log(result[1]); // 打印"2020"
// console.log(result[2]); // 打印"01"
// console.log(result[3]); // 打印"05"
// 现在可以通过指定分组的名称，增加代码可读性，便于维护：
var pattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u
var result = pattern.exec('2020-01-05')
console.log(result.groups.year) // 打印"2020"
// console.log(result.groups.month);        // 打印"01"
// console.log(result.groups.day);          // 打印"05"
// 分组命名还可以和 String.prototype.replace 方法结合：
var reDate = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
var d = '2020-01-05'
var USADate = d.replace(reDate, '$<month>-$<day>-$<year>')
// console.log(USADate);

// ?<= 匹配以开头的 还有其他作用
;/(?<=test)/.test('12321test')

// match 分组   默认分组匹配后会存入缓存 可通过 RegExp.$1 获取
var reg = /(\d{4})-(\d{2})-(\d{2})/
var str = '2020-05-20 16:30'
var res = reg.exec(str) // ['2020-05-20','2020','05','20']
// match 分组别名
var reg = /(?<s1>\d{4})-(?<s2>\d{2})-(?<s3>\d{2})/
var res = reg.exec(str) //['2020-05-20','2020','05','20',groups: {s1: "2020", s2: "05", s3: "20"}]

//  反向引用 使用 \n 表示使用第 n 个分组匹配到的值，比如 \1 表示第 1 个分组：
// 特殊情况：\10 表示的是第 10 个分组，若要匹配 \ 和 0 时，使用 (?:\1)0 或 \1(?:0)。
var r = /\d{4}(-|\/|\.)\d{2}\1\d{2}/
r.test('2019-03-15') // \1 指代-
r.test('2019/03/15') // \1 指代/
r.test('2019.03.15') // \1 指代.
r.test('2019-03/15') // false

/* 练习 */
// http://www.qq.com  // 通过

// http://www.qq.com.cn  // 不通过

// http://www.qq.com/a/b  // 通过

// http://www.qq.com?a=1  // 通过

// http://www.123qq.com?a=1  // 不通过

// http://www.baidu.com?redirect=http://www.qq.com/a 不通过

var rge = /^https?:\/\/w+\.qq\.com[^.]*$/
// console.log(rge.test('http://www.qq.com'));
// console.log(rge.test('http://www.qq.com.cn'));
// console.log(rge.test('http://www.qq.com/a/b'));
// console.log(rge.test('http://www.qq.com?a=1'));
// console.log(rge.test('http://www.qq123.com?a=1'));
// console.log(rge.test('http://www.baidu.com?redirect=http://www.qq.com/a'))

// 十六进制颜色值匹配
var r = /#[0-9a-fA-F]{6}|#[0-9a-fA-F]{3}/g
var s = '#ffaacc #Ff00DD #fFF #01d #9Gd'
s.match(r) // ["#ffaacc", "#Ff00DD", "#fFF", "#01d"]

// 时间和日期匹配
// 时间 12:23 或 01:09
var r = /^([01][0-9]|[2][0-3]):[0-5][0-9]$/
r.test('23:25') // true
r.test('03:05') // true

// 时间 12:23 或 1:9
var r = /^(0?[0-9]|1[0-9]|[2][0-3]):(0?[0-9]|[1-5][0-9])$/
r.test('23:25') // true
r.test('03:05') // true
r.test('3:5') // true

// 日期 yyyy-mm-dd
var r = /^[0-9]{4}-(0[1-9]|[1][0-2])-(0[1-9]|[12][0-9]|3[01])$/
r.test('2019-09-19') // true
r.test('2019-09-32') // false

// 系统路径匹配
var r = /^[a-zA-Z]:\\([^\\:*<>|"?\r\n/]+\\)*([^\\:*<>|"?\r\n/]+)?$/
r.test('C:\\document\\leo\\a.png') // true
r.test('C:\\document\\leo\\') // true
r.test('C:\\document') // true
r.test('C:\\') // true

// 提取 <div id="leo" class="good"></id> 中的 id="leo" ：
var r1 = /id=".*"/ // tips1 \.包含",所以贪婪会匹配到最后一个“
var r2 = /id=".*?"/ // tips2 惰性匹配
var r3 = /id="[^"]*"/ // tips3 最优

var s = '<div id="leo" class="good"></id>'
// s.match(r1)[0];  // id="leo" class="good"
// s.match(r2)[0];  // id="leo"
// s.match(r3)[0];  // id="leo"

// 将 yyyy-mm-dd 转成 mm/dd/yyyy。
var reg = /(\d{4})-(\d{2})-(\d{2})/
'2019-03-14'.replace(reg, '$2/$3/$1') // 03/14/2019

// 替换为指定格式
'1(3)2(4)'.replace(/\(([^\(\)]+)\)/g, '<span>$1</span>') //"1<span>2</span>3<span>4</span>"

// 首字母大写
'my world'.replace(/\b\w/g, v => v.toUpperCase())
// 全部大写
'my world'.replace(/\b\w+\b/g, v => v.toUpperCase())

// 找出字符串中连续出行最多的字符
'a bb ccc ddd eee e'.match(/(.)\1+/g) // ['bb', 'ccc', 'ddd', 'eee']
